﻿using System;

public class ChannelNoise : PapuChannel
{
    public long accCount = 1L;
    public long accValue;
    public int envDecayCounter;
    public bool envDecayDisable;
    public bool envDecayLoopEnable;
    public int envDecayRate;
    public bool envReset;
    public int envVolume;
    public bool isEnabled_Renamed_Field;
    public int lengthCounter;
    public bool lengthCounterEnable;
    public int masterVolume;
    internal PAPU papu;
    public int progTimerCount;
    public int progTimerMax;
    public int randomBit;
    public int randomMode;
    public int sampleValue;
    public bool shiftNow;
    public int shiftReg;
    public int tmp;

    public ChannelNoise(PAPU papu)
    {
        this.papu = papu;
        this.shiftReg = 0x4000;
    }

    public virtual void clockEnvDecay()
    {
        if (this.envReset)
        {
            this.envReset = false;
            this.envDecayCounter = this.envDecayRate + 1;
            this.envVolume = 15;
        }
        else if (--this.envDecayCounter <= 0)
        {
            this.envDecayCounter = this.envDecayRate + 1;
            if (this.envVolume > 0)
            {
                this.envVolume--;
            }
            else
            {
                this.envVolume = this.envDecayLoopEnable ? 15 : 0;
            }
        }
        this.masterVolume = this.envDecayDisable ? this.envDecayRate : this.envVolume;
        this.updateSampleValue();
    }

    public virtual void clockLengthCounter()
    {
        if (this.lengthCounterEnable && (this.lengthCounter > 0))
        {
            this.lengthCounter--;
            if (this.lengthCounter == 0)
            {
                this.updateSampleValue();
            }
        }
    }

    public virtual void destroy()
    {
        this.papu = null;
    }

    public virtual void reset()
    {
        this.progTimerCount = 0;
        this.progTimerMax = 0;
        this.isEnabled_Renamed_Field = false;
        this.lengthCounter = 0;
        this.lengthCounterEnable = false;
        this.envDecayDisable = false;
        this.envDecayLoopEnable = false;
        this.shiftNow = false;
        this.envDecayRate = 0;
        this.envDecayCounter = 0;
        this.envVolume = 0;
        this.masterVolume = 0;
        this.shiftReg = 1;
        this.randomBit = 0;
        this.randomMode = 0;
        this.sampleValue = 0;
        this.tmp = 0;
    }

    public virtual void updateSampleValue()
    {
        if (this.isEnabled_Renamed_Field && (this.lengthCounter > 0))
        {
            this.sampleValue = this.randomBit * this.masterVolume;
        }
    }

    public virtual void writeReg(int address, int value_Renamed)
    {
        if (address == 0x400c)
        {
            this.envDecayDisable = (value_Renamed & 0x10) != 0;
            this.envDecayRate = value_Renamed & 15;
            this.envDecayLoopEnable = (value_Renamed & 0x20) != 0;
            this.lengthCounterEnable = (value_Renamed & 0x20) == 0;
            this.masterVolume = this.envDecayDisable ? this.envDecayRate : this.envVolume;
        }
        else if (address == 0x400e)
        {
            this.progTimerMax = this.papu.getNoiseWaveLength(value_Renamed & 15);
            this.randomMode = value_Renamed >> 7;
        }
        else if (address == 0x400f)
        {
            this.lengthCounter = this.papu.getLengthMax(value_Renamed & 0xf8);
            this.envReset = true;
        }
    }

    public virtual bool Enabled
    {
        get
        {
            return this.isEnabled_Renamed_Field;
        }
        set
        {
            this.isEnabled_Renamed_Field = value;
            if (!value)
            {
                this.lengthCounter = 0;
            }
            this.updateSampleValue();
        }
    }

    public virtual int LengthStatus
    {
        get
        {
            if ((this.lengthCounter != 0) && this.isEnabled_Renamed_Field)
            {
                return 1;
            }
            return 0;
        }
    }
}

